package eu.daxiongmao.skills.model;

import eu.daxiongmao.skills.util.constant.EntityFieldSize;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * User group.
 *
 * @author Guillaume Diaz
 * @version 1.0 - January 2014
 */
@XmlRootElement
@Entity
@Table(name = "users_groups")
public class UserGroup implements Serializable {

    /**
     * Object ID in database.
     */
    @XmlElement(required = false)
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @XmlElement(required = false)
    @Column(name = "description", length = EntityFieldSize.VARCHAR_BIG_TEXT_500, nullable = true, unique = false)
    private String description;

    @XmlElement(required = true)
    @Size(min = 1, max = EntityFieldSize.VARCHAR_SMALL_SIZE_50)
    @Column(name = "name", nullable = false, unique = true, length = EntityFieldSize.VARCHAR_SMALL_SIZE_50)
    private String name;

    /**
     * <p>
     * List of group's permission(s).<br/>
     * Each group can have zero or N permission(s). Each permission matches an application feature.
     * </p>
     * <p>
     * This is a join table. <br/>
     * The 'GROUP_ID' column refers to the GROUP, while the 'PERMISSION_ID' column refers to the PERMISSION.<br/>
     * Note that for the [ @ ManyToMany ] all the mapping is done here.
     * </p>
     */
    @XmlElement(required = false)
    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinTable(name = "groups_permissions", joinColumns = {
        @JoinColumn(name = "group_id", referencedColumnName = "id")}, inverseJoinColumns = {
        @JoinColumn(name = "permission_id", referencedColumnName = "id")})
    private List<Permission> permissions;

    /**
     * <p>
     * The role's members.
     * </p>
     * <p>
     * This is the corresponding relation of the {@link User#getGroups()}. <br/>
     * To make bi-directional links through JoinTable, you must repeat the annotation with owner reference.<br/>
     * see: <a href="http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany">source</a>
     * </p>
     */
    @XmlElement(required = false)
    @ManyToMany(mappedBy = "groups", fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    private List<User> users;

    @Override
    public final boolean equals(final Object target) {
        // Check param
        if (target == null) {
            return false;
        }
        if (getClass() != target.getClass()) {
            return false;
        }

        // Name must be unique
        UserGroup other = (UserGroup) target;
        return other.getName() != null && this.name != null && other.getName().equalsIgnoreCase(this.getName());
    }

    public String getDescription() {
        return description;
    }

    public String getName() {
        String target = name;
        if (name != null) {
            target = target.trim();
        }
        return target;
    }

    public List<Permission> getPermissions() {
        if (permissions == null) {
            this.permissions = new ArrayList<>();
        }
        return permissions;
    }

    public List<User> getUsers() {
        if (users == null) {
            users = new ArrayList<>();
        }
        return users;
    }

    @Override
    public final int hashCode() {
        int hash = 0;
        if (name != null) {
            hash += this.name.trim().hashCode();
        }
        return hash;
    }

    public void setDescription(final String description) {
        this.description = description;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public void setPermissions(final List<Permission> permissions) {
        if (permissions != null) {
            this.permissions = permissions;
        }
    }

    public void setUsers(final List<User> users) {
        if (users != null) {
            this.users = users;
        }
    }

    public Long getId() {
        return id;
    }

    public void setId(final Long id) {
        this.id = id;
    }

    @Override
    public final String toString() {
        StringBuilder log = new StringBuilder("User Group # ");
        if (id != null && id > 0) {
            log.append("ID: ").append(id).append(" | ");
        }

        log.append("Name: ").append(name);
        if (description != null) {
            log.append(" | ").append(description);
        }

        return log.toString();
    }
}
